using System;
using Yahtzee.Game;

namespace Yahtzee.Console
{
    public abstract class Speler
    {
        public static void Main(String[] args)
        {
            int keuze = 0;
            Scanner input;
            do
            {
                System.Console.WriteLine("Welkom bij Yahtzee. Wilt u:");
                System.Console.WriteLine("1. Interactief spelen (dus zelf)");
                System.Console.WriteLine("2. Automatisch spelen (quick test)");
                input = new Scanner(System.Console.In);
                keuze = input.nextInt();
            } while (!(keuze == 1 || keuze == 2));
            Speler app = null;
            switch (keuze)
            {
                case 1:
                    app = new SpelerInteractief();
                    break;
                case 2:
                    app = new SpelerAutomatisch();
                    break;
            }
            app.speelYahtzee();
            // done
            input.close();
#if DEBUG
            System.Console.WriteLine("hit enter to quit");
            System.Console.ReadLine();
#endif
        }

        public Speler()
        {
        }

        public void speelYahtzee()
        {
            Spel spel = new Spel();
            System.Console.WriteLine("Spel gestart");
            while (spel.spelNietAfgelopen())
            {
                // start volgende beurt
                System.Console.WriteLine("Start beurt");
                spel.volgendeBeurt();
                // Gooi met de dobbelstenen
                spel.gooiMetDobbelstenen();
                int[] dobbelstenen = spel.geefOgen();
                dumpDobbelstenen(dobbelstenen, spel.getHuidigeBeurtnr(),
                        spel.getHuidigeWorpnr());
                // vraag of gebruiker tevreden is en een combinatie gaat kiezen,
                // anders dobbelstenen vastzetten
                while (spel.getHuidigeWorpnr() < 3 && !vraagGebruikerTevreden())
                {
                    bool[] zetvast = vraagWelkeDobbelstenenVast(dobbelstenen,
                            spel.getHuidigeBeurtnr(), spel.getHuidigeWorpnr());
                    spel.zetDobbelstenenVast(zetvast);
                    spel.gooiMetDobbelstenen();
                    dobbelstenen = spel.geefOgen();
                    dumpDobbelstenen(dobbelstenen, spel.getHuidigeBeurtnr(),
                            spel.getHuidigeWorpnr());
                }
                Scorecombinatie keuze = kiesEenVrijeCombinatie(spel
                        .geefVrijeCombinaties());
                spel.vulCombinatieIn(keuze);
            }
            System.Console.WriteLine("U heeft " + spel.getTotaalScore() + " punten.");
            System.Console.WriteLine("Spel is afgelopen");
            spel.print(System.Console.Out);
        }

        private Scorecombinatie kiesEenVrijeCombinatie(Scorecombinatie[] combinaties)
        {
            System.Console.WriteLine("De volgende combinaties zijn nog vrij: ");
            for (int i = 0; i < combinaties.Length; i++)
            {
                System.Console.WriteLine((i + 1) + ". " + combinaties[i]);
            }
            int keuze = stelIntVraag("Welke combinatie wilt u gebruiken?", 1,
                    combinaties.Length);
            return combinaties[keuze - 1];
        }

        private bool[] vraagWelkeDobbelstenenVast(int[] dobbelstenen,
                int beurtnr, int worpnr)
        {
            bool[] zetvast = new bool[dobbelstenen.Length];
            for (int i = 0; i < zetvast.Length; i++)
                zetvast[i] = false;
            dumpDobbelstenen(dobbelstenen, beurtnr, worpnr);
            do
            {
                for (int i = 0; i < dobbelstenen.Length; i++)
                {
                    zetvast[i] = stelJaNeeVraag("Moet dobbelsteen " + (i + 1)
                            + " vastgezet worden?");
                }
            } while (!vraagOfVastgezetOke(dobbelstenen, zetvast));

            return zetvast;
        }

        private bool vraagOfVastgezetOke(int[] dobbelstenen, bool[] zetvast)
        {
            System.Console.WriteLine("De volgende dobbelstenen zijn vastgezet: ");
            for (int i = 0; i < dobbelstenen.Length; i++)
            {
                System.Console.WriteLine("Dobbelsteen " + (i + 1) + " met waarde "
                        + dobbelstenen[i] + " is " + (zetvast[i] ? "wel" : "niet")
                        + " vastgezet");
            }
            return stelJaNeeVraag("Wilt u met deze set dobbelen? (J/N)");
        }

        private bool vraagGebruikerTevreden()
        {
            String vraag = "Wilt u de huidige worp gebruiken bij een combinatie? (J/N): ";
            return stelJaNeeVraag(vraag);
        }

        private void dumpDobbelstenen(int[] dobbelstenen, int beurtnr, int worpnr)
        {
            System.Console.WriteLine("Resultaat van worp " + worpnr + " van beurt "
                    + beurtnr + ":");
            for (int i = 0; i < dobbelstenen.Length; i++)
            {
                System.Console.WriteLine("  dobbelsteen " + i + ": " + dobbelstenen[i]);
            }
        }

        protected abstract bool stelJaNeeVraag(String vraag);

        protected abstract int stelIntVraag(String vraag, int min, int max);

    }
}